summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend/spirv/spirv_emit_context.cpp')
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.cpp51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
index 0442adc83..a27f2f73a 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp
@@ -480,6 +480,7 @@ EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_inf
DefineTextures(program.info, texture_binding, bindings.texture_scaling_index);
DefineImages(program.info, image_binding, bindings.image_scaling_index);
DefineAttributeMemAccess(program.info);
+ DefineWriteStorageCasLoopFunction(program.info);
DefineGlobalMemoryFunctions(program.info);
DefineRescalingInput(program.info);
DefineRenderArea(program.info);
@@ -877,6 +878,56 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
}
}
+void EmitContext::DefineWriteStorageCasLoopFunction(const Info& info) {
+ if (profile.support_int8 && profile.support_int16) {
+ return;
+ }
+ if (!info.uses_int8 && !info.uses_int16) {
+ return;
+ }
+
+ AddCapability(spv::Capability::VariablePointersStorageBuffer);
+
+ const Id ptr_type{TypePointer(spv::StorageClass::StorageBuffer, U32[1])};
+ const Id func_type{TypeFunction(void_id, ptr_type, U32[1], U32[1], U32[1])};
+ const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type)};
+ const Id pointer{OpFunctionParameter(ptr_type)};
+ const Id value{OpFunctionParameter(U32[1])};
+ const Id bit_offset{OpFunctionParameter(U32[1])};
+ const Id bit_count{OpFunctionParameter(U32[1])};
+
+ AddLabel();
+ const Id scope_device{Const(1u)};
+ const Id ordering_relaxed{u32_zero_value};
+ const Id body_label{OpLabel()};
+ const Id continue_label{OpLabel()};
+ const Id endloop_label{OpLabel()};
+ const Id beginloop_label{OpLabel()};
+ OpBranch(beginloop_label);
+
+ AddLabel(beginloop_label);
+ OpLoopMerge(endloop_label, continue_label, spv::LoopControlMask::MaskNone);
+ OpBranch(body_label);
+
+ AddLabel(body_label);
+ const Id expected_value{OpLoad(U32[1], pointer)};
+ const Id desired_value{OpBitFieldInsert(U32[1], expected_value, value, bit_offset, bit_count)};
+ const Id actual_value{OpAtomicCompareExchange(U32[1], pointer, scope_device, ordering_relaxed,
+ ordering_relaxed, desired_value, expected_value)};
+ const Id store_successful{OpIEqual(U1, expected_value, actual_value)};
+ OpBranchConditional(store_successful, endloop_label, continue_label);
+
+ AddLabel(endloop_label);
+ OpReturn();
+
+ AddLabel(continue_label);
+ OpBranch(beginloop_label);
+
+ OpFunctionEnd();
+
+ write_storage_cas_loop_func = func;
+}
+
void EmitContext::DefineGlobalMemoryFunctions(const Info& info) {
if (!info.uses_global_memory || !profile.support_int64) {
return;